#region imported Namespaces
using System;
using System.Data;
using System.Data.SqlClient;
using System.Text;

using BO = PHSRAG.Insight21.BusinessObjects;
using Utility = PHSRAG.Utility;
using ICachePolicy = PHSRAG.Insight21.Policy.ICachePolicy;
using GenerateKey = PHSRAG.Insight21.BusinessObjects.ModuleKey;
#endregion

namespace PHSRAG.Insight21.Admin
{
	/// <summary>
	/// The DirectAccessRights business object represents a user's access rights to individual 
	/// resources.  As of Version 2.1 those resources can be protocols and/or agreements.
	/// </summary>
	public class DirectAccessRights : BO.TransactionalBusinessObject
	{
		#region Constants
		private const string DirectAccessRightsTableName = "DirectAccessRights";
		private const string RecordListTableName = "RecordList";
		private static string DirectAccessRightsKey = GenerateKey.MakeKey("DirectAccessRights_B47F7777-1BBC-4955-8A95-126DC85D9C76",GenerateKey.Admin);
		#endregion

		#region Instance Variables
		private SqlCommand	updateCommand;
		private SqlCommand	insertCommand;
		private SqlCommand	deleteCommand;
		#endregion

		#region Public Properties

		/// <summary>
		/// Gets the DataTable that contains a users direct access rights details by module
		/// and access right type.
		/// </summary>
		public DataTable RightsDetails
		{
			get 
			{
				return DataContainer.Tables[DirectAccessRightsTableName];
			}
		}

		/// <summary>
		/// Gets DataTable that is essentially a list of all the records that a user has access to.
		/// </summary>
		public DataTable RecordList
		{
			get 
			{
				return DataContainer.Tables[RecordListTableName];
			}
			set 
			{
				if (DataContainer.Tables.Contains(RecordListTableName))
					DataContainer.Tables.Remove(RecordListTableName);

				DataContainer.Tables.Add(value);
			}
		}

		#endregion

		#region Constructor
		/// <summary>
		/// Initialize the state of this object and create commands to handle insert/delete/update.
		/// </summary>
		public DirectAccessRights(DataSet dataSet, ICachePolicy cachePolicy) : base(cachePolicy)
		{
			DataContainer = dataSet;
			CreateCommands();
		}

//		/// <summary>
//		/// Initialize the data containner.
//		/// </summary>
//		public DirectAccessRights(ICachePolicy cachePolicy) : base(cachePolicy)
//		{
//			DataContainer = new DataSet();
//		}
		#endregion

		#region Base Methods
		public override void Cache()
		{
			CachePolicy.Cache(DirectAccessRightsKey, this);
		}

		public override void UnCache()
		{
			CachePolicy.UnCache(DirectAccessRightsKey);
		}

		/// <summary>
		/// Loads the data container with a domain user's direct access rights to resources. If 
		/// a PI id and/or keygiver id is specified, the result set is limited to resources belonging to 
		/// the specified PI and/or resources relevant to the keygiver's organizations.  It is possible
		/// that the user does not have any direct access resources resulting in an empty result set.
		/// </summary>
		/// <param name="connectionString">The connection string to the data source.</param>
		/// <param name="args">Arguments that are expected to be passed into the method are:
		///						DomainUserId - represents the user who's direct rights we are loading.
		///						PIDomainUserId - if we need to filter the resultset to only those
		///										records that a particular PI owns, otherwise 0.
		///						KeyGiverDomainUserID - if we need to filter the resultset to only those
		///										records that belong to orgs that a particular domainuser
		///										is keygiver for, otherwise 0.
		///</param>
		public override void Load( string connectionString, params object[] args )
		{
			if ( args.Length != 3 )
			{
				throw new Exception ("DirectAccessRights Load expects three arguments." );
			}		

			try
			{	
				Utility.DataAccess.LoadDataSet(DataContainer, DirectAccessRightsTableName, 
					connectionString, "GetUserDirectAccessRights",
					Utility.DataAccess.BuildSqlParameterArray(
						"@domainUserId", SqlDbType.Int, (int)args[0]
						,"@piDomainUserId", SqlDbType.Int, (int)args[1] 
						,"@keyGiverDomainUserId", SqlDbType.Int, (int)args[2]));

				if ( !DataContainer.Tables.Contains(DirectAccessRightsTableName))
					throw new Exception("Failed to load direct access rights information.");

				Utility.DataAccess.LoadDataSet(DataContainer, RecordListTableName, 
					connectionString, "GetUserDirectAccessRightsRecordDetails",
					Utility.DataAccess.BuildSqlParameterArray(
						"@domainUserId", SqlDbType.Int, (int)args[0]
						,"@piDomainUserId", SqlDbType.Int, (int)args[1] 
						,"@keyGiverDomainUserId", SqlDbType.Int, (int)args[2]));

				if ( !DataContainer.Tables.Contains(RecordListTableName))
					throw new Exception("Failed to load direct access rights information.");


			}
			catch( Exception e)
			{
				Utility.ExceptionReport.WriteToEventLog ("DirectAccessRights", e, true, Utility.ExceptionReport.ReportType.Error);
				throw e;
			}
		}
		/// <summary>
		/// Persists ApplicationUser state to the database.
		/// </summary>
		/// <param name="connectionString">Specifies database connection information.</param>
		public override void Save(SqlTransaction transaction, params object[] args)
		{
			try
			{
				ExecuteUpdate(transaction);
			}
			catch (Exception e)
			{
				Utility.ExceptionReport.WriteToEventLog ("DirectAccessRights", e, true, Utility.ExceptionReport.ReportType.Error);
				throw e;
			}
		}

		#endregion

		#region Private Methods
		/// <summary>
		/// Create the set of SqlCommand objects used for the insertion, deletion, and updates made on
		/// the associated DataTable. Notice that each command is initialized to invoke a stored
		/// procedure implying that each command may have its own set of parameters in line with that
		/// stored procedure.
		/// </summary>
		private void CreateCommands()
		{
			insertCommand = new SqlCommand();
			insertCommand.CommandText = "ChangeDirectResourceAccess";
			insertCommand.CommandType = CommandType.StoredProcedure;
			insertCommand.CommandTimeout = Convert.ToInt32(Utility.Settings.GetKeyValue("Database.Insight.CommandTimeout", "0"));
			insertCommand.Parameters.Add("@domainUserId", SqlDbType.Int).SourceColumn = "FwkDomainUserId";
			insertCommand.Parameters.Add("@resourceId", SqlDbType.Int).SourceColumn = "ResourceId";
			insertCommand.Parameters.Add("@accessRightBitmask", SqlDbType.Int).SourceColumn = "AccessRightBitmask";
			insertCommand.Parameters.Add("@comments", SqlDbType.VarChar).SourceColumn = "Comments";

			updateCommand = new SqlCommand();
			updateCommand.CommandText = "UpdateDirectAccessDetails";
			updateCommand.CommandType = CommandType.StoredProcedure;
			updateCommand.CommandTimeout = Convert.ToInt32(Utility.Settings.GetKeyValue("Database.Insight.CommandTimeout", "0"));
			updateCommand.Parameters.Add("@domainUserId", SqlDbType.Int).SourceColumn = "FwkDomainUserId";
			updateCommand.Parameters.Add("@resourceId", SqlDbType.Int).SourceColumn = "ResourceId";
			updateCommand.Parameters.Add("@accessRightBitmask", SqlDbType.Int).SourceColumn = "AccessRightBitmask";
			updateCommand.Parameters.Add("@isContact", SqlDbType.Int).SourceColumn = "Is Contact";
			updateCommand.Parameters.Add("@comments", SqlDbType.VarChar).SourceColumn = "Comment";

			deleteCommand = new SqlCommand();
			deleteCommand.CommandText = "DeleteDirectAccessRights";
			deleteCommand.CommandType = CommandType.StoredProcedure;
			deleteCommand.CommandTimeout = Convert.ToInt32(Utility.Settings.GetKeyValue("Database.Insight.CommandTimeout", "0"));
			deleteCommand.Parameters.Add("@domainUserId", SqlDbType.Int).SourceColumn = "FwkDomainUserId";
			deleteCommand.Parameters.Add("@resourceId", SqlDbType.Int).SourceColumn = "ResourceId";
		}

		/// <summary>
		/// Hits the database to persist the changes to the DataContainer.
		/// </summary>
		/// <param name="transaction"></param>
		private void ExecuteUpdate(SqlTransaction transaction)
		{
			SqlDataAdapter adapter = new SqlDataAdapter();

			deleteCommand.Connection = transaction.Connection;				
			insertCommand.Connection = transaction.Connection;				
			updateCommand.Connection = transaction.Connection;

			deleteCommand.Transaction = transaction;
			insertCommand.Transaction = transaction;
			updateCommand.Transaction = transaction;
	
			adapter.DeleteCommand = deleteCommand;
			adapter.InsertCommand = insertCommand;
			adapter.UpdateCommand = updateCommand;

			adapter.Update(DataContainer, RecordListTableName);
		}
			

		#endregion
	}
}
